package caramcraft;

import java.util.LinkedList;

import math.geom2d.Vector2D;
import jnibwapi.JNIBWAPI;
import jnibwapi.model.Unit;
import jnibwapi.types.OrderType;
import jnibwapi.types.TechType;
import jnibwapi.types.WeaponType;

public class Medic extends SCUnit {
	private TechType heal = bwapi.getTechType(TechType.TechTypes.Healing
			.getID());
	private Medic otherMedic = null;
	private int healId1 = OrderType.OrderTypes.MedicHeal1.getID();
	private int healId2 = OrderType.OrderTypes.MedicHeal2.getID();
	private Tank followTank = null;

	public Medic(Unit unit, JNIBWAPI bwapi) {
		super(unit, bwapi, bwapi.getWeaponType(WeaponType.WeaponTypes.None
				.getID()));
	}

	public Medic(Unit unit, JNIBWAPI bwapi, LinkedList<SCUnit> myUnits,
			LinkedList<Unit> myBuildings, LinkedList<SCUnit> enemyUnits,
			LinkedList<Unit> enemyBuildings) {
		super(unit, bwapi, bwapi.getWeaponType(WeaponType.WeaponTypes.None
				.getID()), myUnits, myBuildings, enemyUnits, enemyBuildings);
	}

	public void step(long frame) {
		if (isSleep(frame))
			return;
		// search for the other medic
		if (otherMedic == null)
			getOtherMedic();

		// keep a little distance to other medic
		Vector2D moveTo = this.getPosition();
		if (otherMedic != null && !otherMedic.isDead()) {
			double distance = getDistance(otherMedic.getUnit());
			if (distance < 50) {
				moveTo = moveTo.plus(otherMedic.getPosition()
						.minus(this.getPosition()).opposite());
				this.move(moveTo);
				sleep(frame,2);
				return;
			}
		}

		if (!isHealing()) {
			// heal the other medic first if necessary
			if (otherMedic != null && otherMedic.getHealthPercent() < 0.95) {
				this.heal(otherMedic);
				sleep(frame, 2);
				return;
			}
			// don't heal the same target
			int otherMedicHealId = -1;
			if( otherMedic != null )
				otherMedicHealId = otherMedic.getHealingTarget();
			// check if we can heal other marines
			Integer minHealth = Integer.MAX_VALUE;
			Marine bestMarine = null;
			for (SCUnit u : this.myUnits) {
				if (u instanceof Marine && u.getHealthPercent() < 0.99 && !u.isDead()
						&& (bestMarine == null || u.getHealth() < minHealth)
						&& u.getID() != otherMedicHealId) {
					minHealth = u.getHealth();
					bestMarine = (Marine) u;
				}
			}
			// if we found a marine, then heal him
			if (bestMarine != null) {
				this.heal(bestMarine);
				sleep(frame, 2);
				return;
			}
		}
		// stay near tanks
		if( followTank == null )
			getTankToFollow();
		if( followTank != null )
		{
			follow(followTank.me);
			sleep(frame,2);
			return;
		}
	}

	public boolean isHealing() {
		int orderId = me.getOrderID();
		return orderId == healId1 || orderId == healId2;
	}
	
	public int getHealingTarget()
	{
		return isHealing() ? me.getTargetUnitID() : -1;
	}

	public void heal(SCUnit target) {
		bwapi.useTech(me.getID(), heal.getID(), target.getID());
	}

	public void getOtherMedic() {
		for (SCUnit u : this.myUnits) {
			if (u instanceof Medic && u.getID() != me.getID()) {
				this.otherMedic = (Medic) u;
				return;
			}
		}
	}
	
	private void getTankToFollow()
	{
		int otherMedicTankId = -1;
		if( otherMedic != null && otherMedic.followTank != null)
			otherMedicTankId = otherMedic.followTank.getID();
		
		for( SCUnit u : this.myUnits )
		{
			if( u instanceof Tank && u.getID() != otherMedicTankId )
			{
				followTank = (Tank)u;
				break;
			}
		}
	}
}
